package com.chujian.framework.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import com.chujian.framework.core.IId;
import com.chujian.framework.core.base.BaseService;

import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据填充回显工具类
 */
public class EchoUtil {

    /**
     * 通用数据回显填充
     *
     * @param targetList  需要填充的数据
     * @param idCol       对象的id属性
     * @param objCol      对象的赋值属性
     * @param dataService 获取需要填充的数据的service
     * @param <T>
     */
    public static <T> void echo(List<T> targetList, String idCol, String objCol, BaseService<? extends IId> dataService) {
        echo(targetList, idCol, dataService, (item, value) -> {
            Method setMethod = getWriteMethod(item.getClass(), objCol);
            invokeSetMethod(setMethod, item, value);
        });
    }

    /**
     * 通用数据填充
     *
     * @param targetList  需要填充的数据
     * @param idCol       目标对象的id属性
     * @param dataService 获取需要填充的数据的service
     * @param fullCompose 自定义填充
     * @param <T>         原item类型
     * @param <V>         填充对象的类型
     */
    @SuppressWarnings("unchecked")
    public static <T, V> void echo(List<T> targetList, String idCol, BaseService<? extends IId> dataService, IEchoCallback<T, V> fullCompose) {
        if (CollUtil.isEmpty(targetList)) return;
        Class<?> entityClass = targetList.get(0).getClass();
        Method getMethod = getReadMethod(entityClass, idCol);
        // # 获取ids
        List<Long> ids = targetList
                .stream()
                .map(item -> invokeGetMethodReturnLongValue(getMethod, item))
                .distinct()
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(ids)) {
            // # 获取数据
            List<? extends IId> fullList = dataService.listByIds(ids);
            for (T data : targetList) {
                Long id = invokeGetMethodReturnLongValue(getMethod, data);
                V fullObj = (V) CollUtil.findOne(fullList, e -> e.getId().equals(id));
                if (null != fullObj) {
                    // # 执行填充
                    fullCompose.doEcho(data, fullObj);
                }
            }
        }
    }

    // ########## 通用方法

    private static Long invokeGetMethodReturnLongValue(Method method, Object obj) {
        try {
            Object invoke = method.invoke(obj);
            return ((Long) invoke);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void invokeSetMethod(Method method, Object obj, Object value) {
        try {
            method.invoke(obj, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Method getReadMethod(Class<?> clazz, String fieldName) {
        return ReflectUtil.getMethodByNameIgnoreCase(clazz, "get" + fieldName);
    }

    private static Method getWriteMethod(Class<?> clazz, String fieldName) {
        return ReflectUtil.getMethodByNameIgnoreCase(clazz, "set" + fieldName);
    }


    /**
     * 回显回调
     *
     * @param <T> 原item类型
     * @param <V> 填充对象的类型
     */
    public interface IEchoCallback<T, V> {

        /**
         * 执行填充
         *
         * @param item
         * @param value
         */
        void doEcho(T item, V value);

    }
}
